package middleware

import (
	"blog/errmsg"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
	"time"
)

/**
jwt:Header(alg + type) + Payload(contain three claims) + Signature(header + payload + secret)
jwt地址：https://www.cnblogs.com/jiujuan/p/11403066.html
middleware介绍：https://docs.lvrui.io/2019/01/27/gin%E6%B7%BB%E5%8A%A0%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%AD%E9%97%B4%E4%BB%B6/
 */

var(
	secret = "15#81"  //salt 加盐
	expireTime = 3 * time.Minute  //token过期时间
)

/**
自定义载荷宣称(数据)
 */
type myClaims struct {
	jwt.StandardClaims
	Username string `json:"username"`
	Password string `json:"password"`
}

//生成jwt token
func GetToken(username,password string)(string,int){
	claims := &myClaims{
		jwt.StandardClaims{
						 Issuer:"ginblog",
						 IssuedAt:time.Now().Unix(),
						 ExpiresAt:time.Now().Add(expireTime).Unix(),
					},
		username,
		password,
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256,claims)
	signedToken,err := token.SignedString([]byte(secret))
	if err!=nil {
		return err.Error(),errmsg.FAIL
	}
	return signedToken,errmsg.SUCCESS
}

//验证jwt token
func verifyToken(strToken string)(*myClaims,int){
	token,err := jwt.ParseWithClaims(strToken,&myClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(secret),nil
	})
	if err!=nil {
		return nil,errmsg.FAIL
	}
	claims,ok := token.Claims.(*myClaims)
	if !ok{
		return nil,errmsg.FAIL
	}
	if claims.Valid()!=nil{
		return nil,errmsg.FAIL
	}
	return claims,errmsg.SUCCESS
}

func TokenVerifyMiddleware()gin.HandlerFunc{
	return func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token == ""{
			c.Abort()
			c.JSON(http.StatusOK,gin.H{
				"code":errmsg.FAIL,
				"msg":"please pass in token",
				"data":"",
			})
			return
		}
		//Bearer auth认证
		array := strings.SplitN(token," ",2)
		if len(array)!=2 && array[0]!="Bearer"{
			c.Abort()
			c.JSON(http.StatusOK,gin.H{
				"code":errmsg.FAIL,
				"msg":"token type error",
				"data":"",
			})
			return
		}
		_,code := verifyToken(array[1])
		if code == errmsg.FAIL{
			c.Abort()
			c.JSON(http.StatusOK,gin.H{
				"code":errmsg.FAIL,
				"msg":"token invalid",
				"data":"",
			})
		}else {
			c.Next()
		}
	}
}